package cn.yuyiling.jelly.qa.service.impl;

import cn.yuyiling.jelly.kgai.api.KnowledgeAIService;
import cn.yuyiling.jelly.qa.api.AnswerService;
import cn.yuyiling.jelly.qa.api.CommentService;
import cn.yuyiling.jelly.qa.mongodb.entity.Answer;
import cn.yuyiling.jelly.qa.mongodb.entity.Question;
import cn.yuyiling.jelly.qa.mongodb.repository.AnswerRepository;
import cn.yuyiling.jelly.qa.mongodb.repository.QuestionRepository;
import cn.yuyiling.jelly.sr.api.RankService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@DubboService
public class AnswerServiceImpl implements AnswerService {
    private static final Logger logger = LoggerFactory.getLogger(AnswerServiceImpl.class);

    private static final String KEY_PREFIX = "view:answer:";
    private static final String SUMMARY_KEY = "view:answer:top24h";

    @Autowired
    private AnswerRepository answerRepository;
    @Autowired
    private QuestionRepository questionRepository;
    @Autowired
    private CommentService commentService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @DubboReference
    private KnowledgeAIService knowledgeAIService;
    @DubboReference(scope = "remote")
    private RankService rankService;

    @Override
    public Answer createAnswer(String questionId, Answer answer) {
        Optional<Question> optionalQuestion = questionRepository.findById(questionId);
        if(optionalQuestion.isPresent()){
            Question question = optionalQuestion.get();
            answer.setParentId(question.getId());
            answer.setPath(question.getPath() + question.getId() + "/");
            answer.setDepth(question.getDepth() + 1);
            answer.setCreatedAt(new Date());
            Answer savedAnswer = answerRepository.save(answer);
            Answer evaluatedAnswer = knowledgeAIService.evaluateAnswer(savedAnswer);
            Answer result = answerRepository.save(evaluatedAnswer);
            rankService.updateWeeklyActiveScore(result);
            return result;
        }else {
            throw new RuntimeException("问题不存在，ID: " + questionId);
        }
    }

    @Override
    public Answer likeAnswer(String id) {
        return answerRepository.findById(id)
                .map(answer -> {
                    answer.setLikes(answer.getLikes() + 1);
                    return answerRepository.save(answer);
                })
                .orElseThrow(() -> new RuntimeException("Answer not found"));
    }

    @Override
    public Answer dislikeAnswer(String id) {
        return answerRepository.findById(id)
                .map(answer -> {
                    answer.setDislikes(answer.getDislikes() + 1);
                    return answerRepository.save(answer);
                })
                .orElseThrow(() -> new RuntimeException("Answer not found"));
    }

    @Override
    public Answer updateAnswer(String id, Answer updatedAnswer) {
        logger.info("updating answer with ID: {}", id);
        Optional<Answer> optionalAnswer = answerRepository.findById(id);
        if(optionalAnswer.isPresent()){
            Answer answer = optionalAnswer.get();
            answer.setContent(updatedAnswer.getContent());
            answer.setKnowledgePoints(updatedAnswer.getKnowledgePoints());
            answer.setMetadata(updatedAnswer.getMetadata());
            answer.setUpdatedAt(new Date());
            return answerRepository.save(answer);
        }else {
            throw new RuntimeException("回答不存在，ID: " + id);
        }
    }

    @Override
    public void deleteAnswersByQuestionId(String questionId) {
        // 查找所有path中包含questionId的回答
        List<Answer> answers = answerRepository.findByPathContaining("/" + questionId + "/");
        // 批量删除这些回答
        answerRepository.deleteAll(answers);
    }

    @Override
    public void deleteAnswerAndRelatedData(String answerId) {
        // 删除回答
        answerRepository.deleteById(answerId);
        // 删除与该回答相关的所有评论
        commentService.deleteCommentsByAnswerId(answerId);
    }

    @Override
    public List<Answer> getTop5HighLikedAnswers() {
        return answerRepository.findTop5ByOrderByLikesDesc();
    }

    @Override
    public List<Answer> getAnswersByQuestionId(String questionId) {
        return answerRepository.findByPathContaining("/" + questionId + "/");
    }

    @Override
    public Answer getAnswerById(String id) {
        Optional<Answer> optionalAnswer = answerRepository.findById(id);
        if(optionalAnswer.isPresent()){
            Answer answer = optionalAnswer.get();
            return answer;
        }else {
            throw new RuntimeException("回答不存在，ID: " + id);
        }
    }


    @Override
    public Answer viewAnswerById(String id) {
        String hourKey = getHourKey(LocalDateTime.now());
        if (!redisTemplate.hasKey(hourKey)) {
            redisTemplate.opsForZSet().add(hourKey, id, 0);
            redisTemplate.expire(hourKey, Duration.ofHours(25));
        }
        redisTemplate.opsForZSet().incrementScore(hourKey, id, 1);
        return getAnswerById(id);
    }

    private String getHourKey(LocalDateTime time) {
        return KEY_PREFIX + time.format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
    }

    @Override
    public List<String> get24HourTopViewAnswer(int count) {
        Set<ZSetOperations.TypedTuple<String>> set = redisTemplate.opsForZSet()
                .reverseRangeWithScores(SUMMARY_KEY, 0, count - 1);
        if (set == null) return Collections.emptyList();
        List<String> result = new ArrayList<>();
        for (ZSetOperations.TypedTuple<String> item : set) {
            result.add(item.getValue() + " (" + item.getScore().intValue() + ")");
        }
        return result;
    }

    @Override
    public void refreshTop24hViewAnswerRanking() {
        logger.info("start refresh Top 24 hours View Answer Ranking");
        List<String> keys = new ArrayList<>();
        for (int i = 0; i < 24; i++) {
            keys.add(getHourKey(LocalDateTime.now().minusHours(i)));
        }
        redisTemplate.opsForZSet().unionAndStore(keys.get(0), keys.subList(1, keys.size()), SUMMARY_KEY);
        redisTemplate.expire(SUMMARY_KEY, Duration.ofHours(1));
    }

}